﻿#region << 文件说明 >>
/*----------------------------------------------------------------
 * 命名空间：Vampirewal.Core.WPF.Theme.CustomControl.Transfer
 * 唯一标识：005dceb1-0ac1-45ff-b6a4-8fb25a853d1f
 * 文件名：Transfer
 * 
 * 创建者：杨程
 * 电子邮箱：235160615@qq.com
 * 创建时间：2025/6/17 9:24:12
 * 版本：V1.0.0
 * 描述：
 *
 * ----------------------------------------------------------------
 * 修改人：
 * 时间：
 * 修改说明：
 *
 * 版本：V1.0.1
 *----------------------------------------------------------------*/
#endregion << 文件说明 >>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Documents;


namespace Vampirewal.Core.WPF.Theme;

/// <summary>
/// 穿梭框
/// </summary>
public partial class Transfer : Control
{
    static Transfer()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(Transfer), new FrameworkPropertyMetadata(typeof(Transfer)));
    }

    private ResourceDictionary res
    {
        get
        {
            return new ResourceDictionary() { Source = new Uri("pack://application:,,,/Vampirewal.Core.WPF.Theme;component/Theme.xaml", UriKind.RelativeOrAbsolute) };
        }
    }



    /// <summary>   
    /// 构造函数
    /// </summary>
    public Transfer()
    {
        //构造函数
        var TransferStyle = res["TransferStyle"] as Style;

        this.Style = TransferStyle;

    }


    private ListBox SourceList { get; set; }
    private ListBox TargetList { get; set; }


    private Button MoveRight { get; set; }
    private Button MoveAllRight { get; set; }
    private Button MoveLeft { get; set; }
    private Button MoveAllLeft { get; set; }


    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        if (SourceList == null) 
        { 
            SourceList = this.Template.FindName("SourceList", this) as ListBox;
            SourceList.Loaded += (s, e) =>
            {
                if (!string.IsNullOrEmpty(GroupByPropertyNames))
                {
                    BuildListBoxGroup(s as ListBox);
                }
                
            };
        }
        if (TargetList == null)
        {
            TargetList = this.Template.FindName("TargetList", this) as ListBox;
            TargetList.Loaded += (s, e) =>
            {
                if (!string.IsNullOrEmpty(GroupByPropertyNames))
                {
                    BuildListBoxGroup(s as ListBox);
                }

            };
        }

        MoveRight = this.Template.FindName("MoveRight", this) as Button;
        MoveRight.Click += (s, e) =>
        {
            MoveItems(SourceList.SelectedItems, SourceItems, TargetItems);
        };

        MoveAllRight = this.Template.FindName("MoveAllRight", this) as Button;
        MoveAllRight.Click += (s, e) =>
        {
            MoveItems(SourceItems, SourceItems, TargetItems);
        };

        MoveLeft = this.Template.FindName("MoveLeft", this) as Button;
        MoveLeft.Click += (s, e) =>
        {
            MoveItems(TargetList.SelectedItems, TargetItems, SourceItems, false);
        };

        MoveAllLeft = this.Template.FindName("MoveAllLeft", this) as Button;
        MoveAllLeft.Click += (s, e) =>
        {
            MoveItems(TargetItems, TargetItems, SourceItems, false);
        };

    }


    // 数据转移逻辑
    private void MoveItems(IEnumerable items, IList source, IList target, bool sourceTotarget = true)
    {
        var itemsToRemove = new ArrayList();
        if (sourceTotarget)
        {
            foreach (var item in items)
            {
                if (this.IsTransedToRemoveSource)
                    itemsToRemove.Add(item);

                if (SourceToTargetCommand != null)
                {
                    SourceToTargetCommand?.Execute(item);
                }
                else
                {
                    target.Add(item);
                }
            }

            if (this.IsTransedToRemoveSource)
            {
                foreach (var item in itemsToRemove)
                {
                    source.Remove(item);
                }
            }
        }
        else
        {
            foreach (var item in items)
            {

                itemsToRemove.Add(item);
                if (this.IsTransedToRemoveSource)
                    target.Add(item);
            }

            foreach (var item in itemsToRemove)
            {
                TargetToSourceCommand?.Execute(item);

                source.Remove(item);
            }
        }



    }



    /// <summary>
    /// 生成默认数据源
    /// </summary>
    /// <returns></returns>
    private static IList CreateDefaultSourceItems() => new ObservableCollection<object>();

    #region 左侧数据源

    #region 左侧数据源
    /// <summary>
    /// 左侧数据源
    /// </summary>
    public IList SourceItems
    {
        get => (IList)GetValue(SourceItemsProperty);
        set => SetValue(SourceItemsProperty, value);
    }

    public static readonly DependencyProperty SourceItemsProperty =
        DependencyProperty.Register("SourceItems", typeof(IList), typeof(Transfer), new System.Windows.PropertyMetadata(CreateDefaultSourceItems()));
    #endregion

    #region 是否允许在移动之后，移除数据源中的数据
    /// <summary>
    /// 是否允许在移动之后，移除数据源中的数据
    /// </summary>
    public bool IsTransedToRemoveSource
    {
        get { return (bool)GetValue(IsTransedToRemoveSourceProperty); }
        set { SetValue(IsTransedToRemoveSourceProperty, value); }
    }

    // Using a DependencyProperty as the backing store for IsTransedToRemoveSource.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty IsTransedToRemoveSourceProperty =
        DependencyProperty.Register("IsTransedToRemoveSource", typeof(bool), typeof(Transfer), new System.Windows.PropertyMetadata(true));
    #endregion

    #region 选择模式
    /// <summary>
    /// 选择模式
    /// </summary>
    public SelectionMode SelectionMode
    {
        get { return (SelectionMode)GetValue(SelectionModeProperty); }
        set { SetValue(SelectionModeProperty, value); }
    }

    // Using a DependencyProperty as the backing store for SelectionMode.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SelectionModeProperty =
        DependencyProperty.Register("SelectionMode", typeof(SelectionMode), typeof(Transfer), new PropertyMetadata(SelectionMode.Single));
    #endregion

    #region 数据源的项模版
    public DataTemplate SourceItemTemplate
    {
        get { return (DataTemplate)GetValue(SourceItemTemplateProperty); }
        set { SetValue(SourceItemTemplateProperty, value); }
    }

    // Using a DependencyProperty as the backing store for SourceItemTemplate.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SourceItemTemplateProperty =
        DependencyProperty.Register("SourceItemTemplate", typeof(DataTemplate), typeof(Transfer), new System.Windows.PropertyMetadata(null, OnSourceItemTemplateCallback));

    private static void OnSourceItemTemplateCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        //var tf = d as Transfer;
        //if (e.NewValue != null && e.NewValue is DataTemplate dt && dt != null)
        //{
        //    tf.SourceList.ItemTemplate = dt;
        //}
    }
    #endregion

    #region 数据源到目标数据源的命令
    /// <summary>
    /// 数据源到目标数据源的命令
    /// </summary>
    public ICommand SourceToTargetCommand
    {
        get { return (ICommand)GetValue(SourceToTargetCommandProperty); }
        set { SetValue(SourceToTargetCommandProperty, value); }
    }

    // Using a DependencyProperty as the backing store for SourceToTargetCommand.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SourceToTargetCommandProperty =
        DependencyProperty.Register("SourceToTargetCommand", typeof(ICommand), typeof(Transfer), new System.Windows.PropertyMetadata(null));
    #endregion

    #region 数据源滚动到目标位置
    public object SourceScrollToItem
    {
        get { return (object)GetValue(SourceScrollToItemProperty); }
        set { SetValue(SourceScrollToItemProperty, value); }
    }

    // Using a DependencyProperty as the backing store for SourceScrollToItem.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SourceScrollToItemProperty =
        DependencyProperty.Register("SourceScrollToItem", typeof(object), typeof(Transfer), new PropertyMetadata(null, OnSourceScrollToItemChangedCallback));

    private static void OnSourceScrollToItemChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var tf = d as Transfer;

        if (!tf.SourceList.Items.Contains(e.NewValue)) return;

        var item = e.NewValue;

        tf.SourceList.ScrollIntoView(item);

        var container = tf.SourceList.ItemContainerGenerator.ContainerFromItem(item) as ListBoxItem;

        // 如果需要同时选中该项
        tf.SourceList.SelectedItem = item;



        container?.BringIntoView();

    }
    #endregion

    #endregion

    #region 右侧数据源

    #region 接收框数据源
    /// <summary>
    /// 接收框数据源
    /// </summary>
    public IList TargetItems
    {
        get => (IList)GetValue(TargetItemsProperty);
        set => SetValue(TargetItemsProperty, value);
    }

    public static readonly DependencyProperty TargetItemsProperty =
        DependencyProperty.Register("TargetItems", typeof(IList), typeof(Transfer), new System.Windows.PropertyMetadata(CreateDefaultSourceItems()));
    #endregion

    #region 接收框的项模版
    public DataTemplate TargetItemTemplate
    {
        get { return (DataTemplate)GetValue(TargetItemTemplateProperty); }
        set { SetValue(TargetItemTemplateProperty, value); }
    }

    // Using a DependencyProperty as the backing store for TargetItemTemplate.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty TargetItemTemplateProperty =
        DependencyProperty.Register("TargetItemTemplate", typeof(DataTemplate), typeof(Transfer), new System.Windows.PropertyMetadata(null, OnTargetItemTemplateCallback));

    private static void OnTargetItemTemplateCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        //var tf = d as Transfer;
        //if (e.NewValue != null && e.NewValue is DataTemplate dt && dt != null)
        //{
        //    tf.TargetList.ItemTemplate = dt;
        //}
    }
    #endregion


    public ICommand TargetToSourceCommand
    {
        get { return (ICommand)GetValue(TargetToSourceCommandProperty); }
        set { SetValue(TargetToSourceCommandProperty, value); }
    }

    // Using a DependencyProperty as the backing store for TargetToSourceCommand.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty TargetToSourceCommandProperty =
        DependencyProperty.Register("TargetToSourceCommand", typeof(ICommand), typeof(Transfer), new System.Windows.PropertyMetadata(null));


    #endregion

    #region 中间按钮

    private static Style GetMoveButtonBaseStyle(string PathGeometryKey)
    {
        Style style = new Style(typeof(Button))
        {
            Setters =
            {
                new Setter(Button.WidthProperty, 40d),
                new Setter(Button.HeightProperty, 30d),
                new Setter(Button.MarginProperty, new Thickness(5)),
                new Setter(Button.ContentProperty, new System.Windows.Shapes.Path()
                {
                    Width=20,
                    Height=20,
                    Fill=Brushes.Black,
                    RenderTransformOrigin=new Point(0.5d,0.5d),
                    Stretch= Stretch.Fill,
                    Data=Application.Current.Resources[PathGeometryKey] as PathGeometry
                }),
            }
        };

        return style;
    }

    #region 向右箭头
    public Style MoveRightButtonStyle
    {
        get { return (Style)GetValue(MoveRightButtonStyleProperty); }
        set { SetValue(MoveRightButtonStyleProperty, value); }
    }

    // Using a DependencyProperty as the backing store for MoveRightButtonStyle.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty MoveRightButtonStyleProperty =
        DependencyProperty.Register("MoveRightButtonStyle", typeof(Style), typeof(Transfer), new PropertyMetadata(MoveRightButtonDefaultStyle, OnMoveRightButtonStyleChangeCallback));

    private static void OnMoveRightButtonStyleChangeCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var tf = d as Transfer;
        if (e.NewValue is Style newStyle)
        {
            if (newStyle.TargetType != null && !typeof(Button).IsAssignableFrom(newStyle.TargetType))
            {
                // 恢复为默认样式
                tf.SetValue(MoveRightButtonStyleProperty, e.OldValue ?? MoveRightButtonDefaultStyle);
            }
        }
        else
        {
            // 恢复为默认样式
            tf.SetValue(MoveRightButtonStyleProperty, e.OldValue ?? MoveRightButtonDefaultStyle);
        }
    }

    private static Style MoveRightButtonDefaultStyle => GetMoveButtonBaseStyle("TransfromRight5");
    #endregion

    #region 全部向右箭头


    [Description("设置'全部右移'按钮的样式 (必须针对Button类型)")]
    public Style MoveAllRightButtonStyle
    {
        get { return (Style)GetValue(MoveAllRightButtonStyleProperty); }
        set { SetValue(MoveAllRightButtonStyleProperty, value); }
    }

    // Using a DependencyProperty as the backing store for MoveAllRightButtonStyle.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty MoveAllRightButtonStyleProperty =
        DependencyProperty.Register("MoveAllRightButtonStyle", typeof(Style), typeof(Transfer), new PropertyMetadata(MoveAllRightButtonDefaultStyle, OnMoveAllRightButtonStyleChangeCallback));

    private static void OnMoveAllRightButtonStyleChangeCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var tf = d as Transfer;
        if (e.NewValue is Style newStyle)
        {
            if (newStyle.TargetType != null && !typeof(Button).IsAssignableFrom(newStyle.TargetType))
            {
                // 恢复为默认样式
                tf.SetValue(MoveAllRightButtonStyleProperty, e.OldValue ?? MoveAllRightButtonDefaultStyle);
            }
        }
        else
        {
            // 恢复为默认样式
            tf.SetValue(MoveAllRightButtonStyleProperty, e.OldValue ?? MoveAllRightButtonDefaultStyle);
        }
    }

    private static Style MoveAllRightButtonDefaultStyle => GetMoveButtonBaseStyle("TransfromRight4");
    #endregion

    #region 向左箭头



    public Style MoveLeftButtonStyle
    {
        get { return (Style)GetValue(MoveLeftButtonStyleProperty); }
        set { SetValue(MoveLeftButtonStyleProperty, value); }
    }

    // Using a DependencyProperty as the backing store for MoveLeftButtonStyle.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty MoveLeftButtonStyleProperty =
        DependencyProperty.Register("MoveLeftButtonStyle", typeof(Style), typeof(Transfer), new PropertyMetadata(MoveLeftButtonDefaultStyle, OnMoveLeftButtonStyleChangedCallback));

    private static void OnMoveLeftButtonStyleChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var tf = d as Transfer;
        if (e.NewValue is Style newStyle)
        {
            if (newStyle.TargetType != null && !typeof(Button).IsAssignableFrom(newStyle.TargetType))
            {
                // 恢复为默认样式
                tf.SetValue(MoveLeftButtonStyleProperty, e.OldValue ?? MoveLeftButtonDefaultStyle);
            }
        }
        else
        {
            // 恢复为默认样式
            tf.SetValue(MoveLeftButtonStyleProperty, e.OldValue ?? MoveLeftButtonDefaultStyle);
        }
    }

    private static Style MoveLeftButtonDefaultStyle => GetMoveButtonBaseStyle("TransfromLeft3");
    #endregion

    #region 全部向左箭头



    public Style MoveAllLeftButtonStyle
    {
        get { return (Style)GetValue(MoveAllLeftButtonStyleProperty); }
        set { SetValue(MoveAllLeftButtonStyleProperty, value); }
    }

    // Using a DependencyProperty as the backing store for MoveAllLeftButtonStyle.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty MoveAllLeftButtonStyleProperty =
        DependencyProperty.Register("MoveAllLeftButtonStyle", typeof(Style), typeof(Transfer), new PropertyMetadata(MoveAllLeftButtonDefaultStyle, OnMoveAllLeftButtonStyleChangedCallback));

    private static void OnMoveAllLeftButtonStyleChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var tf = d as Transfer;
        if (e.NewValue is Style newStyle)
        {
            if (newStyle.TargetType != null && !typeof(Button).IsAssignableFrom(newStyle.TargetType))
            {
                // 恢复为默认样式
                tf.SetValue(MoveAllLeftButtonStyleProperty, e.OldValue ?? MoveAllLeftButtonDefaultStyle);
            }
        }
        else
        {
            // 恢复为默认样式
            tf.SetValue(MoveAllLeftButtonStyleProperty, e.OldValue ?? MoveAllLeftButtonDefaultStyle);
        }
    }

    private static Style MoveAllLeftButtonDefaultStyle => GetMoveButtonBaseStyle("TransfromLeft2");
    #endregion

    #endregion

    #region 左右数据列表样式



    public Style TransferListStyle
    {
        get { return (Style)GetValue(TransferListStyleProperty); }
        set { SetValue(TransferListStyleProperty, value); }
    }

    // Using a DependencyProperty as the backing store for TransferListStyle.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty TransferListStyleProperty =
        DependencyProperty.Register("TransferListStyle", typeof(Style), typeof(Transfer), new PropertyMetadata(null, OnTransferListStyleChangedCallback));

    private static void OnTransferListStyleChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {

    }

    private static Style GetListBoxDefaultStyle()
    {
        Style style = new Style(typeof(ListBox));








        var EmptyListBoxStyle = Application.Current.Resources["EmptyListBox"] as Style;

        //style.Triggers.Add(new Trigger()
        //{
        //    Property=ListBox.items
        //});

        return EmptyListBoxStyle;
    }



    #endregion

    #region 数据源的分组

    /// <summary>
    /// 绑定分组名称
    /// </summary>
    public string GroupByPropertyNames
    {
        get { return (string)GetValue(GroupByPropertyNamesProperty); }
        set { SetValue(GroupByPropertyNamesProperty, value); }
    }

    // Using a DependencyProperty as the backing store for GroupByPropertyNames.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty GroupByPropertyNamesProperty =
        DependencyProperty.Register("GroupByPropertyNames", typeof(string), typeof(Transfer), new PropertyMetadata(""));


    private void BuildListBoxGroup(ListBox listBox)
    {
        Style style = res["GroupHeaderStyle"] as Style;

        Style TargetStyle = null;

        var StyleStr = XamlWriter.Save(style);

        StyleStr = StyleStr.Replace("Tag=\"Target\"", "Margin=\"" + "0 0 0 0\" Text=\"{Binding Path=Name}\"").Replace("IsExpanded=\"True\"", "IsExpanded=\"False\" Margin=\"0 0 0 2\" ");

        using (MemoryStream ms = new MemoryStream())
        {
            using (StreamWriter sw = new StreamWriter(ms))
            {
                sw.Write(StyleStr);
                sw.Flush();
                ms.Seek(0, SeekOrigin.Begin);
                TargetStyle = XamlReader.Load(ms) as Style;
            }
        }

        listBox.GroupStyle.Clear();
        listBox.GroupStyle.Add(new GroupStyle()
        {
            ContainerStyle = TargetStyle,
        });

        // 添加分组描述
        ICollectionView view = CollectionViewSource.GetDefaultView(listBox.ItemsSource);
        if (view != null)
        {
            view.GroupDescriptions.Clear();
            foreach (var propertyName in GroupByPropertyNames.Split('-'))
            {
                view.GroupDescriptions.Add(new PropertyGroupDescription(propertyName));
            }
        }


        
    }
    #endregion
}



